package com.tianji.learning.service.impl;

import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.swing.plaf.synth.ColorType;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author Yandel
 * @since 2025-05-26
 */
@RequiredArgsConstructor
@Service
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {

    private final UserClient userClient;
    private final StringRedisTemplate redisTemplate;

    @Override
    public PointsBoardVO queryPointsBoardList(PointsBoardQuery query) {
        //1、获取当前用户
        Long userId = UserContext.getUser();
        //2、判断是当前赛季还是历史赛季   赛季id，为null或者0则代表查询当前赛季
        boolean isCurrentSeason = query.getSeason() == null || query.getSeason() == 0;//true表示当前赛季

        //拼接key
        LocalDate now = LocalDate.now();
        String format = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + format;
        Long season = query.getSeason();
        //3、查询我的排名和积分
        PointsBoard board = isCurrentSeason ? queryMyCurrentBoard(key) : queryMyHistoryBoard(season);
        //4、 分页查询赛季列表
        List<PointsBoard> list = isCurrentSeason ? queryCurrentBoard(key, query.getPageNo(), query.getPageSize()) : queryHistoryBoard(query);
        //5、封装返回VO
        PointsBoardVO vo = new PointsBoardVO();
        vo.setRank(board.getRank());//我的排名
        vo.setPoints(board.getPoints());//我的积分

        //封装用户id集合
        Set<Long> uids = list.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        //调用用户集合  获取用户信息
        List<UserDTO> userList = userClient.queryUserByIds(uids);
        if (userList.isEmpty()) {
            throw new BizIllegalException("用户不存在~");
        }
        //转map  key:用户id    value 用户名称
        Map<Long, String> userDtoMap = userList.stream()
                .collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));

        List<PointsBoardItemVO> voList = new ArrayList<>();
        for (PointsBoard pointsBoard : list) {
            PointsBoardItemVO itemVO = new PointsBoardItemVO();
            itemVO.setPoints(pointsBoard.getPoints());
            itemVO.setRank(pointsBoard.getRank());
            itemVO.setName(userDtoMap.get(pointsBoard.getUserId()));
            voList.add(itemVO);
        }
        vo.setBoardList(voList);

        return vo;
    }


    /**
     * 查询历史赛季排行榜列表
     *
     * @param query
     * @return
     */
    private List<PointsBoard> queryHistoryBoard(PointsBoardQuery query) {
        if (query.getPageNo() <= 0 || query.getPageSize() <= 0) {
            throw new BadRequestException("非法参数");
        }
        int offset = query.getPageNo() - 1;
        List<PointsBoard> list = this.lambdaQuery()
                .eq(PointsBoard::getSeason, query.getSeason())
                .orderByAsc(PointsBoard::getPoints)
                .last("LIMIT" + query.getPageSize() + "OFFSET" + offset)
                .list();
        return list;
    }


    /**
     * 查询当前赛季排行榜列表
     *
     * @param key
     * @param pageNo   页码
     * @param pageSize 条数
     * @return
     */
    public List<PointsBoard> queryCurrentBoard(String key, Integer pageNo, Integer pageSize) {
        //计算start 和stop  下标都是从零开始
        int start = (pageNo - 1) * pageSize;
        int end = start + pageSize - 1;
        //利用zrevrange  按分数倒序  分页查询
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet()
                .reverseRangeWithScores(key, start, end);
        if (CollUtils.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }
        int rank = start + 1;
        List<PointsBoard> list = new ArrayList<>();
        //封装结果返回
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            String value = typedTuple.getValue();//用户id
            Double score = typedTuple.getScore();//总积分值
            if (StringUtils.isBlank(value) || score == null) {
                continue;
            }
            PointsBoard board = new PointsBoard();
            board.setUserId(Long.valueOf(value));
            board.setPoints(score.intValue());
            board.setRank(rank++);
            list.add(board);
        }
        return list;
    }

    /**
     * 查询历史赛季我的积分和排名
     *
     * @param season
     * @return
     */
    private PointsBoard queryMyHistoryBoard(Long season) {
        //获取当前用户id
        Long userId = UserContext.getUser();
        if (season == null) {
            throw new BadRequestException("非法参数");
        }
        PointsBoard board = this.lambdaQuery()
                .eq(PointsBoard::getUserId, userId)
                .eq(PointsBoard::getSeason, season).one();
        if (board == null){
            throw new BizIllegalException("相关排名不存在");
        }
        return board;
    }

    /**
     * 查询当前赛季我的积分和排名
     *
     * @param key
     * @return
     */
    private PointsBoard queryMyCurrentBoard(String key) {
        //获取当前用户id
        Long userId = UserContext.getUser();
        //从redis中获取积分值
        Double score = redisTemplate.opsForZSet().score(key, userId.toString());
        //获取排名 从零开始，需要加一
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());
        PointsBoard board = new PointsBoard();
        board.setPoints(score == null ? 0 : score.intValue());
        board.setRank(rank == null ? 0 : rank.intValue() + 1);

        return board;
    }


    //TODO  定时任务看榜单更新


//    @Override
//    public void createPointsBoardTableBySeason(Integer season) {
//
//    }
}
